package com.juhuixing.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.juhuixing.gateway.config.WhiteListConfig;
import com.juhuixing.gateway.model.HeaderContant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;

/**
 * 功能描述:网关拦截验证权限
 * @author: 刘猛
 * @date: 2019/2/20 17:15
 **/
@Component
@Slf4j
public class PreRequestFilter extends ZuulFilter {

    private static String BEARER = "Bearer";

    private final static AntPathMatcher matcher = new AntPathMatcher();

    @Autowired
    private WhiteListConfig whiteListConfig;

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        //int值来定义过滤器的执行顺序，数值越小优先级越高
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        final String authorizationHeader = request.getHeader(HeaderContant.AUTHORIZATION);
        final String version = request.getHeader(HeaderContant.VERSION);
        final String source = request.getHeader(HeaderContant.SOURCE);
        final String imei = request.getHeader(HeaderContant.IMEI);
        final String deviceInfo = request.getHeader(HeaderContant.DEVICE_INFO);
        String uri = ctx.getRequest().getRequestURI();
        if(antMatchers(uri)){return null;}


        if (HttpMethod.OPTIONS.name().equals(request.getMethod())) {
            return null;
        } else {
            if (StringUtils.isEmpty(authorizationHeader) || !authorizationHeader.startsWith(BEARER)) {
                // Missing or invalid Authorization header
                JSONObject errorResponseMap = new JSONObject();
                errorResponseMap.put("error_message","Missing or invalid Authorization header!");
                errorResponseMap.put("error_code",401);
                denyAccess(ctx,errorResponseMap);
                return errorResponseMap;
            }
            final String token = authorizationHeader.substring(7);
            try {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                /**向下传递用户信息**/
                String userName = (String) authentication.getPrincipal();
                /**此处username是用户的唯一标识 传递至资源服务器 方便查询当前访问用户相关资源**/
                ctx.addZuulRequestHeader(HeaderContant.USERNAME, userName);
                ctx.addZuulRequestHeader(HeaderContant.ACCESS_TOKEN, token);
                ctx.addZuulRequestHeader(HeaderContant.DEVICE_INFO, version);
                ctx.addZuulRequestHeader(HeaderContant.SOURCE, source);
                ctx.addZuulRequestHeader(HeaderContant.IMEI, imei);
                ctx.addZuulRequestHeader(HeaderContant.DEVICE_INFO, deviceInfo);
            } catch ( Exception ex) {
                JSONObject errorResponseMap = new JSONObject();
                errorResponseMap.put("error_message","Invalid token!");
                errorResponseMap.put("error_code",403);
                denyAccess(ctx,errorResponseMap);
                return errorResponseMap;
            }
        }
        return null;
    }

    private void denyAccess(RequestContext ctx, JSONObject authResult) {
        String result = JSON.toJSONString(authResult);
        ctx.setSendZuulResponse(false);
        ctx.setResponseStatusCode(401);
        try {
            ctx.getResponse().getWriter().write(result);
        }catch (Exception e){}
    }

    private boolean antMatchers(String uri) {
        boolean is = false;
        for (String patten : whiteListConfig.getWhiteList()) {
            if (matcher.match(patten,uri)){
                is = true;
                return is;
            }
        }
        return is;
    }
}
